package junior.util.aop.annotation.advisor;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.annotation.AnnotationUtils;

import junior.util.aop.annotation.AnnotationInvoker;
import junior.util.aop.annotation.aspectj.AnnotationInterceptor;

public class AnnotationAdvisor extends StaticMethodMatcherPointcutAdvisor implements InitializingBean {
	private static final long serialVersionUID = 1L;
	 
	private AnnotationInvoker invoker;
	
	@Override
	public void afterPropertiesSet() throws Exception {
		AnnotationInterceptor interceptor = new AnnotationInterceptor();
		interceptor.setInvoker(invoker);
		super.setAdvice(interceptor);
	}
	
	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		Method m = method;

        if ( isAnnotationPresent(m) ) {
            return true;
        }

        //The 'method' parameter could be from an interface that doesn't have the annotation.
        //Check to see if the implementation has it.
        if ( targetClass != null) {
            try {
                m = targetClass.getMethod(m.getName(), m.getParameterTypes());
                if ( isAnnotationPresent(m) ) {
                    return true;
                }
            } catch (NoSuchMethodException ignored) {
                //default return value is false.  If we can't find the method, then obviously
                //there is no annotation, so just use the default return value.
            }
        }

        return false;
    }

    private boolean isAnnotationPresent(Method method) {
    	Class<? extends Annotation>[] supptAnnoClasses = invoker.getSupportAnnotations();
    	
    	for (Class<? extends Annotation> supptAnnoClass : supptAnnoClasses) {
	        Annotation a = AnnotationUtils.findAnnotation(method, supptAnnoClass);
	        if ( a != null ) {
	            return true;
	        }
    	}
    	
        return false;
    }

	public void setInvoker(AnnotationInvoker invoker) {
		this.invoker = invoker;
	}
	
}
